/*----------------------------------------------------------------------------/
  Lovyan GFX - Graphics library for embedded devices.

Original Source:
 https://github.com/lovyan03/LovyanGFX/

Licence:
 [FreeBSD](https://github.com/lovyan03/LovyanGFX/blob/master/license.txt)

Author:
 [lovyan03](https://twitter.com/lovyan03)

Contributors:
 [ciniml](https://github.com/ciniml)
 [mongonta0716](https://github.com/mongonta0716)
 [tobozo](https://github.com/tobozo)
/----------------------------------------------------------------------------*/
#include "Panel_RM68120.hpp"

#include "../Bus.hpp"
#include "../misc/colortype.hpp"
#include "../platforms/common.hpp"

namespace lgfx
{
 inline namespace v1
 {
//----------------------------------------------------------------------------
// ToDo : 初期化コマンド以外は NT35510と共通化する;

  void Panel_RM68120::writeRegister(uint16_t cmd, uint8_t data)
  {
    writeCommand(getSwap16(cmd), 2);
    writeData(data, 1);
  }

  bool Panel_RM68120::init(bool use_reset)
  {
    if (!Panel_LCD::init(use_reset)) return false;

    struct writereg_t
    {
      uint16_t cmd;
      uint8_t data;
    };
    static constexpr const writereg_t regs[] =
    {
      { 0xF000, 0x55 }, { 0xF001, 0xAA }, { 0xF002, 0x52 }, { 0xF003, 0x08 }, { 0xF004, 0x01 },
//GAMMA SETING  RED
      { 0xD100, 0x00 }, { 0xD101, 0x00 }, { 0xD102, 0x1b }, { 0xD103, 0x44 }, { 0xD104, 0x62 }, { 0xD105, 0x00 }, { 0xD106, 0x7b }, { 0xD107, 0xa1 }, { 0xD108, 0xc0 }, { 0xD109, 0xee }, { 0xD10A, 0x55 }, { 0xD10B, 0x10 }, { 0xD10C, 0x2c }, { 0xD10D, 0x43 }, { 0xD10E, 0x57 }, { 0xD10F, 0x55 },
      { 0xD110, 0x68 }, { 0xD111, 0x78 }, { 0xD112, 0x87 }, { 0xD113, 0x94 }, { 0xD114, 0x55 }, { 0xD115, 0xa0 }, { 0xD116, 0xac }, { 0xD117, 0xb6 }, { 0xD118, 0xc1 }, { 0xD119, 0x55 }, { 0xD11A, 0xcb }, { 0xD11B, 0xcd }, { 0xD11C, 0xd6 }, { 0xD11D, 0xdf }, { 0xD11E, 0x95 }, { 0xD11F, 0xe8 },
      { 0xD120, 0xf1 }, { 0xD121, 0xfa }, { 0xD122, 0x02 }, { 0xD123, 0xaa }, { 0xD124, 0x0b }, { 0xD125, 0x13 }, { 0xD126, 0x1d }, { 0xD127, 0x26 }, { 0xD128, 0xaa }, { 0xD129, 0x30 }, { 0xD12A, 0x3c }, { 0xD12B, 0x4A }, { 0xD12C, 0x63 }, { 0xD12D, 0xea }, { 0xD12E, 0x79 }, { 0xD12F, 0xa6 },
      { 0xD130, 0xd0 }, { 0xD131, 0x20 }, { 0xD132, 0x0f }, { 0xD133, 0x8e }, { 0xD134, 0xff },
//GAMMA SETING GREEN
      { 0xD200, 0x00 }, { 0xD201, 0x00 }, { 0xD202, 0x1b }, { 0xD203, 0x44 }, { 0xD204, 0x62 }, { 0xD205, 0x00 }, { 0xD206, 0x7b }, { 0xD207, 0xa1 }, { 0xD208, 0xc0 }, { 0xD209, 0xee }, { 0xD20A, 0x55 }, { 0xD20B, 0x10 }, { 0xD20C, 0x2c }, { 0xD20D, 0x43 }, { 0xD20E, 0x57 }, { 0xD20F, 0x55 },
      { 0xD210, 0x68 }, { 0xD211, 0x78 }, { 0xD212, 0x87 }, { 0xD213, 0x94 }, { 0xD214, 0x55 }, { 0xD215, 0xa0 }, { 0xD216, 0xac }, { 0xD217, 0xb6 }, { 0xD218, 0xc1 }, { 0xD219, 0x55 }, { 0xD21A, 0xcb }, { 0xD21B, 0xcd }, { 0xD21C, 0xd6 }, { 0xD21D, 0xdf }, { 0xD21E, 0x95 }, { 0xD21F, 0xe8 },
      { 0xD220, 0xf1 }, { 0xD221, 0xfa }, { 0xD222, 0x02 }, { 0xD223, 0xaa }, { 0xD224, 0x0b }, { 0xD225, 0x13 }, { 0xD226, 0x1d }, { 0xD227, 0x26 }, { 0xD228, 0xaa }, { 0xD229, 0x30 }, { 0xD22A, 0x3c }, { 0xD22B, 0x4a }, { 0xD22C, 0x63 }, { 0xD22D, 0xea }, { 0xD22E, 0x79 }, { 0xD22F, 0xa6 },
      { 0xD230, 0xd0 }, { 0xD231, 0x20 }, { 0xD232, 0x0f }, { 0xD233, 0x8e }, { 0xD234, 0xff },
//GAMMA SETING BLUE
      { 0xD300, 0x00 }, { 0xD301, 0x00 }, { 0xD302, 0x1b }, { 0xD303, 0x44 }, { 0xD304, 0x62 }, { 0xD305, 0x00 }, { 0xD306, 0x7b }, { 0xD307, 0xa1 }, { 0xD308, 0xc0 }, { 0xD309, 0xee }, { 0xD30A, 0x55 }, { 0xD30B, 0x10 }, { 0xD30C, 0x2c }, { 0xD30D, 0x43 }, { 0xD30E, 0x57 }, { 0xD30F, 0x55 },
      { 0xD310, 0x68 }, { 0xD311, 0x78 }, { 0xD312, 0x87 }, { 0xD313, 0x94 }, { 0xD314, 0x55 }, { 0xD315, 0xa0 }, { 0xD316, 0xac }, { 0xD317, 0xb6 }, { 0xD318, 0xc1 }, { 0xD319, 0x55 }, { 0xD31A, 0xcb }, { 0xD31B, 0xcd }, { 0xD31C, 0xd6 }, { 0xD31D, 0xdf }, { 0xD31E, 0x95 }, { 0xD31F, 0xe8 },
      { 0xD320, 0xf1 }, { 0xD321, 0xfa }, { 0xD322, 0x02 }, { 0xD323, 0xaa }, { 0xD324, 0x0b }, { 0xD325, 0x13 }, { 0xD326, 0x1d }, { 0xD327, 0x26 }, { 0xD328, 0xaa }, { 0xD329, 0x30 }, { 0xD32A, 0x3c }, { 0xD32B, 0x4A }, { 0xD32C, 0x63 }, { 0xD32D, 0xea }, { 0xD32E, 0x79 }, { 0xD32F, 0xa6 },
      { 0xD330, 0xd0 }, { 0xD331, 0x20 }, { 0xD332, 0x0f }, { 0xD333, 0x8e }, { 0xD334, 0xff },
//GAMMA SETING  RED
      { 0xD400, 0x00 }, { 0xD401, 0x00 }, { 0xD402, 0x1b }, { 0xD403, 0x44 }, { 0xD404, 0x62 }, { 0xD405, 0x00 }, { 0xD406, 0x7b }, { 0xD407, 0xa1 }, { 0xD408, 0xc0 }, { 0xD409, 0xee }, { 0xD40A, 0x55 }, { 0xD40B, 0x10 }, { 0xD40C, 0x2c }, { 0xD40D, 0x43 }, { 0xD40E, 0x57 }, { 0xD40F, 0x55 },
      { 0xD410, 0x68 }, { 0xD411, 0x78 }, { 0xD412, 0x87 }, { 0xD413, 0x94 }, { 0xD414, 0x55 }, { 0xD415, 0xa0 }, { 0xD416, 0xac }, { 0xD417, 0xb6 }, { 0xD418, 0xc1 }, { 0xD419, 0x55 }, { 0xD41A, 0xcb }, { 0xD41B, 0xcd }, { 0xD41C, 0xd6 }, { 0xD41D, 0xdf }, { 0xD41E, 0x95 }, { 0xD41F, 0xe8 },
      { 0xD420, 0xf1 }, { 0xD421, 0xfa }, { 0xD422, 0x02 }, { 0xD423, 0xaa }, { 0xD424, 0x0b }, { 0xD425, 0x13 }, { 0xD426, 0x1d }, { 0xD427, 0x26 }, { 0xD428, 0xaa }, { 0xD429, 0x30 }, { 0xD42A, 0x3c }, { 0xD42B, 0x4A }, { 0xD42C, 0x63 }, { 0xD42D, 0xea }, { 0xD42E, 0x79 }, { 0xD42F, 0xa6 },
      { 0xD430, 0xd0 }, { 0xD431, 0x20 }, { 0xD432, 0x0f }, { 0xD433, 0x8e }, { 0xD434, 0xff },
//GAMMA SETING GREEN
      { 0xD500, 0x00 }, { 0xD501, 0x00 }, { 0xD502, 0x1b }, { 0xD503, 0x44 }, { 0xD504, 0x62 }, { 0xD505, 0x00 }, { 0xD506, 0x7b }, { 0xD507, 0xa1 }, { 0xD508, 0xc0 }, { 0xD509, 0xee }, { 0xD50A, 0x55 }, { 0xD50B, 0x10 }, { 0xD50C, 0x2c }, { 0xD50D, 0x43 }, { 0xD50E, 0x57 }, { 0xD50F, 0x55 },
      { 0xD510, 0x68 }, { 0xD511, 0x78 }, { 0xD512, 0x87 }, { 0xD513, 0x94 }, { 0xD514, 0x55 }, { 0xD515, 0xa0 }, { 0xD516, 0xac }, { 0xD517, 0xb6 }, { 0xD518, 0xc1 }, { 0xD519, 0x55 }, { 0xD51A, 0xcb }, { 0xD51B, 0xcd }, { 0xD51C, 0xd6 }, { 0xD51D, 0xdf }, { 0xD51E, 0x95 }, { 0xD51F, 0xe8 },
      { 0xD520, 0xf1 }, { 0xD521, 0xfa }, { 0xD522, 0x02 }, { 0xD523, 0xaa }, { 0xD524, 0x0b }, { 0xD525, 0x13 }, { 0xD526, 0x1d }, { 0xD527, 0x26 }, { 0xD528, 0xaa }, { 0xD529, 0x30 }, { 0xD52A, 0x3c }, { 0xD52B, 0x4a }, { 0xD52C, 0x63 }, { 0xD52D, 0xea }, { 0xD52E, 0x79 }, { 0xD52F, 0xa6 },
      { 0xD530, 0xd0 }, { 0xD531, 0x20 }, { 0xD532, 0x0f }, { 0xD533, 0x8e }, { 0xD534, 0xff },
//GAMMA SETING BLUE
      { 0xD600, 0x00 }, { 0xD601, 0x00 }, { 0xD602, 0x1b }, { 0xD603, 0x44 }, { 0xD604, 0x62 }, { 0xD605, 0x00 }, { 0xD606, 0x7b }, { 0xD607, 0xa1 }, { 0xD608, 0xc0 }, { 0xD609, 0xee }, { 0xD60A, 0x55 }, { 0xD60B, 0x10 }, { 0xD60C, 0x2c }, { 0xD60D, 0x43 }, { 0xD60E, 0x57 }, { 0xD60F, 0x55 },
      { 0xD610, 0x68 }, { 0xD611, 0x78 }, { 0xD612, 0x87 }, { 0xD613, 0x94 }, { 0xD614, 0x55 }, { 0xD615, 0xa0 }, { 0xD616, 0xac }, { 0xD617, 0xb6 }, { 0xD618, 0xc1 }, { 0xD619, 0x55 }, { 0xD61A, 0xcb }, { 0xD61B, 0xcd }, { 0xD61C, 0xd6 }, { 0xD61D, 0xdf }, { 0xD61E, 0x95 }, { 0xD61F, 0xe8 },
      { 0xD620, 0xf1 }, { 0xD621, 0xfa }, { 0xD622, 0x02 }, { 0xD623, 0xaa }, { 0xD624, 0x0b }, { 0xD625, 0x13 }, { 0xD626, 0x1d }, { 0xD627, 0x26 }, { 0xD628, 0xaa }, { 0xD629, 0x30 }, { 0xD62A, 0x3c }, { 0xD62B, 0x4A }, { 0xD62C, 0x63 }, { 0xD62D, 0xea }, { 0xD62E, 0x79 }, { 0xD62F, 0xa6 },
      { 0xD630, 0xd0 }, { 0xD631, 0x20 }, { 0xD632, 0x0f }, { 0xD633, 0x8e }, { 0xD634, 0xff },

//AVDD VOLTAGE SETTING
      { 0xB000, 0x05 },
      { 0xB001, 0x05 },
      { 0xB002, 0x05 },
//AVEE VOLTAGE SETTING
      { 0xB100, 0x05 },
      { 0xB101, 0x05 },
      { 0xB102, 0x05 },

//AVDD Boosting
      { 0xB600, 0x34 },
      { 0xB601, 0x34 },
      { 0xB603, 0x34 },
//AVEE Boosting
      { 0xB700, 0x24 },
      { 0xB701, 0x24 },
      { 0xB702, 0x24 },
//VCL Boosting
      { 0xB800, 0x24 },
      { 0xB801, 0x24 },
      { 0xB802, 0x24 },
//VGLX VOLTAGE SETTING
      { 0xBA00, 0x14 },
      { 0xBA01, 0x14 },
      { 0xBA02, 0x14 },
//VCL Boosting
      { 0xB900, 0x24 },
      { 0xB901, 0x24 },
      { 0xB902, 0x24 },
//Gamma Voltage
      { 0xBc00, 0x00 },
      { 0xBc01, 0xa0 },//vgmp=5.0
      { 0xBc02, 0x00 },
      { 0xBd00, 0x00 },
      { 0xBd01, 0xa0 },//vgmn=5.0
      { 0xBd02, 0x00 },
//VCOM Setting
      { 0xBe01, 0x3d },//3
//ENABLE PAGE 0
      { 0xF000, 0x55 },
      { 0xF001, 0xAA },
      { 0xF002, 0x52 },
      { 0xF003, 0x08 },
      { 0xF004, 0x00 },
//Vivid Color Function Control
      { 0xB400, 0x10 },
//Z-INVERSION
      { 0xBC00, 0x05 },
      { 0xBC01, 0x05 },
      { 0xBC02, 0x05 },

//*************** add on 20111021**********************//
      { 0xB700, 0x22 },//GATE EQ CONTROL
      { 0xB701, 0x22 },//GATE EQ CONTROL
      { 0xC80B, 0x2A },//DISPLAY TIMING CONTROL
      { 0xC80C, 0x2A },//DISPLAY TIMING CONTROL
      { 0xC80F, 0x2A },//DISPLAY TIMING CONTROL
      { 0xC810, 0x2A },//DISPLAY TIMING CONTROL
//*************** add on 20111021**********************//
//PWM_ENH_OE =1
      { 0xd000, 0x01 },
//DM_SEL =1
      { 0xb300, 0x10 },
//VBPDA=07h
      { 0xBd02, 0x07 },
//VBPDb=07h
      { 0xBe02, 0x07 },
//VBPDc=07h
      { 0xBf02, 0x07 },
//ENABLE PAGE 2
      { 0xF000, 0x55 },
      { 0xF001, 0xAA },
      { 0xF002, 0x52 },
      { 0xF003, 0x08 },
      { 0xF004, 0x02 },
//SDREG0 =0
      { 0xc301, 0xa9 },
//DS=14
      { 0xfe01, 0x94 },
//OSC =60h
      { 0xf600, 0x60 },
//TE ON
      { 0x3500, 0x00 },
      { 0xFFFF, 0xFF },
    };

    startWrite();
    for (size_t idx = 0; regs[idx].cmd != 0xFFFF; ++idx)
    {
      writeRegister(regs[idx].cmd, regs[idx].data);
    }

    writeCommand(CMD_SLPOUT, 2); // SLEEP OUT
    _bus->flush();
    delay(100);
    writeCommand(CMD_DISPON, 2); // DISPLY ON
    _bus->flush();

    endWrite();

    return true;
  }

  void Panel_RM68120::setInvert(bool invert)
  {
    _invert = invert;
    startWrite();
    writeCommand((invert ^ _cfg.invert) ? CMD_INVON : CMD_INVOFF, 2);
    _bus->flush();
    endWrite();
  }

  void Panel_RM68120::update_madctl(void)
  {
    if (_bus != nullptr)
    {
      startWrite();
      writeCommand(CMD_COLMOD, 2);
      writeData(getColMod(_write_bits), 1);
      writeCommand(CMD_MADCTL, 2);
      writeData(getMadCtl(_internal_rotation) | (_cfg.rgb_order ? MAD_RGB : MAD_BGR), 1);
      _bus->flush();
      endWrite();
    }
  }

  void Panel_RM68120::setWindow(uint_fast16_t xs, uint_fast16_t ys, uint_fast16_t xe, uint_fast16_t ye)
  {
    bool dlen_16bit = _cfg.dlen_16bit;
    if (dlen_16bit && _has_align_data)
    {
      _bus->writeData(0, 8);
      _has_align_data = false;
    }

    if (xs != _xs || xe != _xe)
    {
      _xs = xs;
      xs += _colstart;
      writeRegister((CMD_CASET << 8) + 0, xs >> 8);
      writeRegister((CMD_CASET << 8) + 1, xs     );
      _xe = xe;
      xe += _colstart;
      writeRegister((CMD_CASET << 8) + 2, xe >> 8);
      writeRegister((CMD_CASET << 8) + 3, xe     );
    }
    if (ys != _ys || ye != _ye)
    {
      _ys = ys;
      ys += _rowstart;
      writeRegister((CMD_RASET << 8) + 0, ys >> 8);
      writeRegister((CMD_RASET << 8) + 1, ys     );
      _ye = ye;
      ye += _rowstart;
      writeRegister((CMD_RASET << 8) + 2, ye >> 8);
      writeRegister((CMD_RASET << 8) + 3, ye     );
    }
    writeCommand(CMD_RAMWR, 2);
  }

  void Panel_RM68120::readRect(uint_fast16_t x, uint_fast16_t y, uint_fast16_t w, uint_fast16_t h, void* dst, pixelcopy_t* param)
  {
    uint_fast16_t bytes = param->dst_bits >> 3;
    auto len = w * h;
    if (!_cfg.readable)
    {
      memset(dst, 0, len * bytes);
      return;
    }

    startWrite();
    setWindow(x, y, x + w - 1, y + h - 1);

    writeCommand(_cmd_ramrd, 2);
    _bus->beginRead(_cfg.dummy_read_pixel);

    if (_bus->busType() == bus_type_t::bus_parallel16)
    { /// 16bitパラレル時の読出しは、RGB3Byte+ダミー1Byteの4Byte単位構成となっているため、ダミーデータの除去処理が必要;
      uint32_t* tmp = (uint32_t*)alloca(len * 4);
      _bus->readBytes((uint8_t*)tmp, len * 4);
      for (size_t idx = 0; idx < len; ++idx)
      {
        param->src_data = &tmp[idx];
        param->src_x32 = 0;
        param->fp_copy(dst, idx, idx + 1, param);
      }
    }
    else
    {
      if (param->no_convert)
      {
        _bus->readBytes((uint8_t*)dst, len * bytes);
      }
      else
      {
        _bus->readPixels(dst, param, len);
      }
    }
    cs_control(true);
    _bus->endRead();

    endWrite();

    if (_in_transaction) { cs_control(false); }
  }

//----------------------------------------------------------------------------
 }
}
